/*—————————————————————————————————————————————————————————— axios封装工具包 ——————————————————————————————————————————————————————————*/
import axios from 'axios'
import commonConfig from '@/common/config/config'

// 导入ts接口
import {
  GetPendingKeyType,
  AddPendingType,
  RemovePendingType,
  HttpErrorStatusHandleType,
} from './interface'

// 声明每次请求的key存储map字典
const pendingMap = new Map()

// 结构出需要的公共数据方便使用
const { ENV, baseURLCollection, devRequestPath } = commonConfig

/**
 * 当前的baseUrl
 */
// -----------------------------------------------------------------------------------------------------------
export const nowBaseUrl = () => {
  // 得到当前的环境类型,如果没有获取到，则默认为本地开发
  const ENVTYPE = process.env[ENV] ?? 'dev'

  // 声明当的请求url中间值，带入 axios默认地址合集 中进行获取对应的请求地址
  let url = baseURLCollection[ENVTYPE]

  // 如果当前是本地环境下，则将此时的dev参数，带入 axios本地请求地址合集 得到需要的请求地址
  ENVTYPE === 'dev' && (url = devRequestPath[url])

  url ??
    console.error(
      `axios默认请求地址baseUrl不存在，请检查axios.config文件夹下对应的配置信息！`
    )

  return url
}

/**
 * 生成唯一的每个请求的唯一key
 */
// -----------------------------------------------------------------------------------------------------------
export const getPendingKey: GetPendingKeyType = (config) => {
  // 结构出需要的字段
  const { url, method, params } = config
  let { data } = config

  // response里面返回的config.data是个字符串对象，先进行解析
  if (typeof data === 'string') data = JSON.parse(data) 

  // 弹出拼接好后的字符串
  return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
}

/**
 * 储存每个请求的唯一cancel回调, 以此为标识
 */
// -----------------------------------------------------------------------------------------------------------
export const addPending: AddPendingType = (config) => {
  // 得到当前接口拼接好后的字符串
  const pendingKey = getPendingKey(config)

  // 如果此时的定义参数中，有 cancelToken 则返回，否则进行手动创建
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      // 如果在存储的map中不存在此时的拼接字符串，则将创建的cancel进行加入map中
      if (!pendingMap.has(pendingKey)) {
        pendingMap.set(pendingKey, cancel)
      }
    })
}

/**
 * 删除重复的请求
 */
// -----------------------------------------------------------------------------------------------------------
export const removePending: RemovePendingType = (config) => {
  // 得到当前接口拼接好后的字符串
  const pendingKey = getPendingKey(config)

  // 如果此时的 拼接字符串，已经在map中
  if (pendingMap.has(pendingKey)) {
    // 获取此时的cancel函数
    const cancelToken = pendingMap.get(pendingKey)
    // 如你不明白此处为什么需要传递pendingKey可以看文章 https://juejin.cn/post/6968630178163458084#heading-28
    cancelToken(pendingKey)
    // 从当前的map中移除此时的成员
    pendingMap.delete(pendingKey)
  }
}

/**
 * 处理异常
 */
// -----------------------------------------------------------------------------------------------------------
export const httpErrorStatusHandle: HttpErrorStatusHandleType = (error) => {
  // 处理被取消的请求
  if (axios.isCancel(error)) return '请求的重复请求：' + error.message

  // 获取对应的错误信息
  // =========================================================================================
  let message = ''
  if (error && error.response) {
    // 同步错误信息
    message =
      commonConfig.errorCode[error.response.status] ??
      '异常问题，请联系管理员！'

    //  额外的特殊操作
    switch (error.response.status) {
      case 401:
        message = '您未登录，或者登录已经超时，请先登录！'
        break
      default:
        break
    }
  }

  // 判断其他额外错误情况
  // =========================================================================================
  if (error.message.includes('timeout')) message = '网络请求超时！'
  if (error.message.includes('Network'))
    message = window.navigator.onLine ? '服务端异常！' : '您断网了！'

  return message
}
